/*
 * msa.h
 *   microstate accounting.  See Documentation/MicrostateAccounting for info.
 *
 * Copyright (c) Peter Chubb 2005
 *  UNSW and National ICT Australia
 * Copyright (c) 2010 MontaVista Software, LLC
 *  Corey Minyard <minyard@mvista.com>, <minyard@acm.org>, <source@mvista.com>
 */

#ifndef RTOS_LINUX_MSA_H
#define RTOS_LINUX_MSA_H

#include <linux/types.h>
#include <linux/basemsa.h>

typedef uint64_t msa_time_t;
/*
 * Tracked states
 */
enum msa_thread_state {
	MSA_UNKNOWN = -1,
	MSA_ONCPU_USER,
	MSA_ONCPU_SYS,
	MSA_INTERRUPTIBLE_SLEEP,
	MSA_UNINTERRUPTIBLE_SLEEP,
	MSA_ONRUNQUEUE,
	MSA_ZOMBIE,
	MSA_STOPPED,
	MSA_INTERRUPTED,
	MSA_PAGING_SLEEP,
	MSA_FUTEX_SLEEP,
	MSA_POLL_SLEEP,

	MSA_NR_STATES /* Must be last */
};

/* Values for "which" in the msa syscall */
#define MSA_THREAD	0 /* Just the current thread */
#define MSA_CHILDREN	1 /* All dead and waited-for threads */
#define MSA_SELF	2 /* All threads in current process */
#define MSA_GET_NOW	3 /* Current MSA timer in the first value */

#ifdef __KERNEL__

#include <linux/compiler.h> /* For __user */

/* Forward definition... */
struct task_struct;

#ifdef CONFIG_RTOS_MICROSTATE_ACCT

#include <linux/cputime_msa.h>

extern struct kmem_cache *microstates_struct_cachep;
extern struct microstates microstate_init_task;

/*
 * Times are tracked for the current task in timers[], and for the
 * current task's children in child_timers[] (accumulated at wait()
 * time).  One of these structures is added to every struct task_struct.
 */
struct microstates {
	enum msa_thread_state cur_state;
	enum msa_thread_state next_state;
	msa_time_t last_change; /* When the last change happened */
	msa_time_t timers[MSA_NR_STATES];
	msa_time_t child_timers[MSA_NR_STATES];
};

void msa_next_state(struct task_struct *p, int state);
void msa_init(struct task_struct *p);
void msa_set_timer(struct task_struct *p, int state);
void msa_irq_exit(int irq_id, int is_going_to_user);
void msa_simple_irq_account(unsigned int irq_id, struct pt_regs *regs);
int msa_get_account_enabled(void);
#else /* CONFIG_RTOS_MICROSTATE_ACCT */
/*
 * Dummy functions to do nothing, for when MICROSTATE_ACCT is configured off.
 */
extern void irq_exit(void);
#define msa_next_state(a, b) do { } while (0)
#endif /* CONFIG_RTOS_MICROSTATE_ACCT */

#if defined(CONFIG_RTOS_MICROSTATE_ACCT) && defined(CONFIG_RTOS_MICROSTATE_ACCT_ON_SYSTEM_CALL)
extern asmlinkage void msa_space_switch(enum msa_thread_state state);
#else
#define msa_space_switch(a) do { } while (0)
#endif

#endif /* __KERNEL__ */

#endif /* RTOS_LINUX_MSA_H */
